﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public interface Primitive {
        bool isIntersect(Ray r, ref double dist);
        Material Material { get; }
        bool isLight();
        Vector3 Position { get; }
        Vector3 assignNormal(Vector3 boundryPoint, Vector3 normalVector);
    }

    public class Plane : Primitive {
        private Vector3 position;
        private Vector3 direction;
        private Material material;
        private bool light;

        public Plane(Vector3 pos, Vector3 dir, bool li) {
            this.position = pos;
            this.direction = dir;
            this.light = li;
            this.material = new Material();
        }
        public Vector3 Position {
            get { return this.position; }
        }
        public Material Material {
            get { return this.material; }
        }
        public bool isLight() {
            return this.light;
        }
        public bool isIntersect(Ray r, ref double dist) {
            Vector3 edge = new Vector3(this.position);
            edge.sub(r.Eye);
            double d = edge.dot(this.direction) / r.Dir.dot(this.direction);
            if ((0 < d && d < dist) == false)
                return false;

            dist = d;
            return true;
        }
        public Vector3 assignNormal(Vector3 bndry, Vector3 normal) {
            return normal.set(this.direction);
        }
    }

    public class Sphere : Primitive {
        private Vector3 position;
        private double radius;
        private Material material;
        private bool light;

        public Sphere(Vector3 pos, double rad, bool li) {
            this.position = pos;
            this.radius = rad;
            this.material = new Material();
            this.light = li;
        }
        public Vector3 Position {
            get { return this.position; }
        }
        public Material Material {
            get { return this.material; }
        }
        public bool isLight() {
            return this.light;
        }
        public bool isIntersect(Ray r, ref double dist) {
            Vector3 v;
            double d, dot, t;

            // d = [V * (Vo - Po)]^2 - |Vo - Po|^2 + r^2 >= 0
            // t = -V * (Vo - Po) - Sqrt(d)
            // P = tV * Vo
            v = new Vector3(r.Eye);
            dot = v.sub(this.position).dot(r.Dir);
            d = dot * dot - v.dot(v) + radius * radius;
            //if (DoubleTester.IsZero(r.Dir[0]) && DoubleTester.IsZero(r.Dir[1]))
            //    System.Diagnostics.Debug.WriteLine("test01");
            
            if ((d > 0) == false)
                return false;

            t = - dot - Math.Sqrt(d);
            if ((0 < t && t < dist) == false)
                return false;

            dist = t;
            return true;
        }
        public Vector3 assignNormal(Vector3 bndry, Vector3 nrml) {
            return nrml.set(bndry).sub(this.position).normalize();
        }
    }
}
